#pragma once
#include <vector>
#include <string>
#include <cstring>
#include <cstdint>
#include <cassert>
using std::size_t;

#define BUFFER_DEFAULT_SIZE 1024
class Buffer
{
private:
    std::vector<char> _buffer;
    size_t _reader_idx;
    size_t _writer_idx;

    size_t Size() const { return _buffer.size(); }
    char *Begin() { return &*_buffer.begin(); }
    const char *Begin() const { return &*_buffer.begin(); }
    size_t HeadIdleSize() const { return _reader_idx; }
    size_t TailIdleSize() const { return Size() - _writer_idx; }
    char *WriteBegin() { return Begin() + _writer_idx; }

    void CheckBufferSize(size_t len)
    {
        // 检查buffer尾部剩余空间是否足够
        if (TailIdleSize() >= len)
            return;

        // 将数据移动到buffer头部
        size_t ras = ReadAbleSize();
        std::copy(ReadBegin(), ReadBegin() + ras, Begin());
        _reader_idx = 0;
        _writer_idx = ras;

        // 检查buffer空余空间是否足够，不够则扩容
        if (TailIdleSize() >= len)
            return;
        else
            _buffer.resize((len / 1024 + 1) * 1024);
    }

public:
    Buffer() : _buffer(BUFFER_DEFAULT_SIZE), _reader_idx(0), _writer_idx(0) {}
    Buffer &operator=(Buffer &bf)
    {
        if (this != &bf)
        {
            Clear();
            Write(bf.ReadBegin(), bf.ReadAbleSize());
        }
        return *this;
    }
    Buffer(const Buffer &bf) : _buffer(BUFFER_DEFAULT_SIZE), _reader_idx(0), _writer_idx(0)
    {
        Write(bf.ReadBegin(), bf.ReadAbleSize());
    }
    ~Buffer() {}

    size_t ReadAbleSize() const { return _writer_idx - _reader_idx; }
    char *ReadBegin() { return Begin() + _reader_idx; }
    const char *ReadBegin() const { return Begin() + _reader_idx; }

    void Write(const void *data, size_t len)
    {
        if (len == 0)
            return;
        CheckBufferSize(len);
        const char *d = (const char *)data;
        std::copy(d, d + len, WriteBegin());
        _writer_idx += len;
    }

    void Write(const std::string &data)
    {
        Write(data.c_str(), data.size());
    }

    void Write(const Buffer &buf)
    {
        Write(buf.ReadBegin(), buf.ReadAbleSize());
    }

    void ConfirmReadSize(size_t len)
    {
        assert(len <= ReadAbleSize());
        _reader_idx += len;
    }

    size_t Read(void *data, size_t len)
    {
        if (len > ReadAbleSize())
            len = ReadAbleSize();
        std::copy(ReadBegin(), ReadBegin() + len, (char *)data);
        return len;
    }

    std::string ReadAsString(size_t len)
    {
        std::string s;
        s.resize(len);
        size_t ret = Read((void *)s.c_str(), len);
        return s;
    }

    std::string GetLine()
    {
        char *pos = (char *)memchr(ReadBegin(), '\n', ReadAbleSize());
        if (!pos)
            return "";

        return ReadAsString(pos - ReadBegin() + 1);
    }

    void Clear()
    {
        _reader_idx = 0;
        _writer_idx = 0;
    }

    bool HasDataRead()
    {
        return ReadAbleSize() > 0;
    }
};